using System;
using System.Collections.Generic;
using System.Linq;
using Urs.Core.Caching;
using Urs.Core.Data;
using Urs.Data.Domain.Stores;

namespace Urs.Services.Stores
{
    public partial class GoodsSpecService : IGoodsSpecService
    {
        #region Constants
        private const string PRODUCTATTRIBUTES_ALL_KEY = "Urs.goodsattribute.all";
        private const string PRODUCTATTRIBUTES_BY_ID_KEY = "Urs.goodsattribute.id-{0}";
        private const string PRODUCTVARIANTATTRIBUTES_ALL_KEY = "Urs.goodsvariantattribute.all-{0}";
        private const string PRODUCTVARIANTATTRIBUTES_BY_ID_KEY = "Urs.goodsvariantattribute.id-{0}";
        private const string PRODUCTVARIANTATTRIBUTES_BY_KEY = "Urs.goodsvariantattribute-{0}-{1}";
        private const string PRODUCTVARIANTATTRIBUTEVALUES_ALL_KEY = "Urs.goodsvariantattributevalue.all-{0}";
        private const string PRODUCTVARIANTATTRIBUTEVALUES_BY_ID_KEY = "Urs.goodsvariantattributevalue.id-{0}";
        private const string PRODUCTATTRIBUTES_PATTERN_KEY = "Urs.goodsattribute.";
        private const string PRODUCTVARIANTATTRIBUTES_PATTERN_KEY = "Urs.goodsvariantattribute.";
        private const string PRODUCTVARIANTATTRIBUTEVALUES_PATTERN_KEY = "Urs.goodsvariantattributevalue.";
        #endregion

        #region Fields

        private readonly IRepository<GoodsSpec> _goodsSpecRepository;
        private readonly IRepository<GoodsSpecMapping> _goodsSpecMappingRepository;
        private readonly IRepository<GoodsSpecCombination> _goodsSpecCombinationRepository;
        private readonly IRepository<GoodsSpecValue> _goodsSpecValueRepository;
        private readonly ICacheManager _cacheManager;


        #endregion

        #region Ctor

        public GoodsSpecService(ICacheManager cacheManager,
            IRepository<GoodsSpec> goodsSpecRepository,
            IRepository<GoodsSpecMapping> goodsSpecMappingRepository,
            IRepository<GoodsSpecCombination> goodsSpecCombinationRepository,
            IRepository<GoodsSpecValue> goodsSpecValueRepository
            )
        {
            _cacheManager = cacheManager;
            _goodsSpecRepository = goodsSpecRepository;
            _goodsSpecMappingRepository = goodsSpecMappingRepository;
            _goodsSpecCombinationRepository = goodsSpecCombinationRepository;
            _goodsSpecValueRepository = goodsSpecValueRepository;
        }

        #endregion

        #region Methods

        #region Goods spec

        public virtual void DeleteGoodsSpec(GoodsSpec goodsSpec)
        {
            if (goodsSpec == null)
                throw new ArgumentNullException("goodsSpec");

            _goodsSpecRepository.Delete(goodsSpec);

            _cacheManager.RemoveByPattern(PRODUCTATTRIBUTES_PATTERN_KEY);
            _cacheManager.RemoveByPattern(PRODUCTVARIANTATTRIBUTES_PATTERN_KEY);
            _cacheManager.RemoveByPattern(PRODUCTVARIANTATTRIBUTEVALUES_PATTERN_KEY);

        }

        public virtual IList<GoodsSpec> GetAllGoodsSpecs(string name = null)
        {
            string key = PRODUCTATTRIBUTES_ALL_KEY;
            var list = _cacheManager.Get(key, () =>
             {
                 var query = from pa in _goodsSpecRepository.Table
                             orderby pa.Name
                             select pa;
                 var goodsSpecs = query.ToList();
                 return goodsSpecs;
             });

            if (!string.IsNullOrEmpty(name))
                return list.Where(q => q.Name.Contains(name)).ToList();

            return list;
        }

        public virtual GoodsSpec GetGoodsSpecById(int goodsSpecId)
        {
            if (goodsSpecId == 0)
                return null;

            string key = string.Format(PRODUCTATTRIBUTES_BY_ID_KEY, goodsSpecId);
            return _cacheManager.Get(key, () =>
            {
                var pa = _goodsSpecRepository.GetById(goodsSpecId);
                return pa;
            });
        }

        public virtual void InsertGoodsSpec(GoodsSpec goodsSpec)
        {
            if (goodsSpec == null)
                throw new ArgumentNullException("goodsSpec");

            _goodsSpecRepository.Insert(goodsSpec);

            _cacheManager.RemoveByPattern(PRODUCTATTRIBUTES_PATTERN_KEY);
            _cacheManager.RemoveByPattern(PRODUCTVARIANTATTRIBUTES_PATTERN_KEY);
            _cacheManager.RemoveByPattern(PRODUCTVARIANTATTRIBUTEVALUES_PATTERN_KEY);

        }

        public virtual void UpdateGoodsSpec(GoodsSpec goodsSpec)
        {
            if (goodsSpec == null)
                throw new ArgumentNullException("goodsSpec");

            _goodsSpecRepository.Update(goodsSpec);

            _cacheManager.RemoveByPattern(PRODUCTATTRIBUTES_PATTERN_KEY);
            _cacheManager.RemoveByPattern(PRODUCTVARIANTATTRIBUTES_PATTERN_KEY);
            _cacheManager.RemoveByPattern(PRODUCTVARIANTATTRIBUTEVALUES_PATTERN_KEY);
        }

        #endregion

        #region Goods spec mappings (goodsSpec)

        public virtual void DeleteGoodsSpecMapping(GoodsSpecMapping goodsSpec)
        {
            if (goodsSpec == null)
                throw new ArgumentNullException("goodsSpec");

            _goodsSpecMappingRepository.Delete(goodsSpec);

            _cacheManager.RemoveByPattern(PRODUCTATTRIBUTES_PATTERN_KEY);
            _cacheManager.RemoveByPattern(PRODUCTVARIANTATTRIBUTES_PATTERN_KEY);
            _cacheManager.RemoveByPattern(PRODUCTVARIANTATTRIBUTEVALUES_PATTERN_KEY);

        }

        public virtual IList<GoodsSpecMapping> GetGoodsSpecMappingByGoodsId(int goodsId)
        {
            string key = string.Format(PRODUCTVARIANTATTRIBUTES_ALL_KEY, goodsId);

            return _cacheManager.Get(key, () =>
            {
                var query = from pva in _goodsSpecMappingRepository.Table
                            orderby pva.Id
                            where pva.GoodsId == goodsId
                            select pva;
                var goodsSpecs = query.ToList();
                return goodsSpecs;
            });
        }

        public virtual GoodsSpecMapping GetGoodsSpecMappingById(int goodsSpecMappingId)
        {
            if (goodsSpecMappingId == 0)
                return null;

            string key = string.Format(PRODUCTVARIANTATTRIBUTES_BY_ID_KEY, goodsSpecMappingId);
            return _cacheManager.Get(key, () =>
            {
                return _goodsSpecMappingRepository.GetById(goodsSpecMappingId);
            });
        }

        public virtual GoodsSpecMapping GetGoodsSpecMapping(int goodsId, int goodsSpecValueId)
        {
            if (goodsSpecValueId == 0 || goodsId == 0)
                return null;

            string key = string.Format(PRODUCTVARIANTATTRIBUTES_BY_KEY, goodsId, goodsSpecValueId);
            return _cacheManager.Get(key, () =>
            {
                return _goodsSpecMappingRepository.Table.FirstOrDefault(q => q.GoodsId == goodsId && q.GoodsSpecValueId == goodsSpecValueId);
            });
        }

        public virtual void InsertGoodsSpecMapping(GoodsSpecMapping goodsSpec)
        {
            if (goodsSpec == null)
                throw new ArgumentNullException("goodsSpec");

            _goodsSpecMappingRepository.Insert(goodsSpec);

            _cacheManager.RemoveByPattern(PRODUCTATTRIBUTES_PATTERN_KEY);
            _cacheManager.RemoveByPattern(PRODUCTVARIANTATTRIBUTES_PATTERN_KEY);
            _cacheManager.RemoveByPattern(PRODUCTVARIANTATTRIBUTEVALUES_PATTERN_KEY);

        }

        public virtual void UpdateGoodsSpecMapping(GoodsSpecMapping goodsSpec)
        {
            if (goodsSpec == null)
                throw new ArgumentNullException("goodsSpec");

            _goodsSpecMappingRepository.Update(goodsSpec);

            _cacheManager.RemoveByPattern(PRODUCTATTRIBUTES_PATTERN_KEY);
            _cacheManager.RemoveByPattern(PRODUCTVARIANTATTRIBUTES_PATTERN_KEY);
            _cacheManager.RemoveByPattern(PRODUCTVARIANTATTRIBUTEVALUES_PATTERN_KEY);
        }

        #endregion

        #region Goods attribute values (goodsSpecValue)

        public virtual void DeleteGoodsSpecValue(GoodsSpecValue goodsSpecValue)
        {
            if (goodsSpecValue == null)
                throw new ArgumentNullException("goodsSpecValue");

            _goodsSpecValueRepository.Delete(goodsSpecValue);

            _cacheManager.RemoveByPattern(PRODUCTATTRIBUTES_PATTERN_KEY);
            _cacheManager.RemoveByPattern(PRODUCTVARIANTATTRIBUTES_PATTERN_KEY);
            _cacheManager.RemoveByPattern(PRODUCTVARIANTATTRIBUTEVALUES_PATTERN_KEY);

        }

        public virtual IList<GoodsSpecValue> GetGoodsSpecValues(int goodsSpecId)
        {
            string key = string.Format(PRODUCTVARIANTATTRIBUTEVALUES_ALL_KEY, goodsSpecId);
            return _cacheManager.Get(key, () =>
            {
                var query = from pvav in _goodsSpecValueRepository.Table
                            orderby pvav.Id
                            where pvav.GoodsSpecId == goodsSpecId
                            select pvav;
                var goodsSpecValues = query.ToList();
                return goodsSpecValues;
            });
        }

        public virtual GoodsSpecValue GetGoodsSpecValueById(int goodsSpecValueId)
        {
            if (goodsSpecValueId == 0)
                return null;

            string key = string.Format(PRODUCTVARIANTATTRIBUTEVALUES_BY_ID_KEY, goodsSpecValueId);
            return _cacheManager.Get(key, () =>
            {
                var pvav = _goodsSpecValueRepository.GetById(goodsSpecValueId);
                return pvav;
            });
        }

        public virtual void InsertGoodsSpecValue(GoodsSpecValue goodsSpecValue)
        {
            if (goodsSpecValue == null)
                throw new ArgumentNullException("goodsSpecValue");

            _goodsSpecValueRepository.Insert(goodsSpecValue);

            _cacheManager.RemoveByPattern(PRODUCTATTRIBUTES_PATTERN_KEY);
            _cacheManager.RemoveByPattern(PRODUCTVARIANTATTRIBUTES_PATTERN_KEY);
            _cacheManager.RemoveByPattern(PRODUCTVARIANTATTRIBUTEVALUES_PATTERN_KEY);
        }

        public virtual void UpdateGoodsSpecValue(GoodsSpecValue goodsSpecValue)
        {
            if (goodsSpecValue == null)
                throw new ArgumentNullException("goodsSpecValue");

            _goodsSpecValueRepository.Update(goodsSpecValue);

            _cacheManager.RemoveByPattern(PRODUCTATTRIBUTES_PATTERN_KEY);
            _cacheManager.RemoveByPattern(PRODUCTVARIANTATTRIBUTES_PATTERN_KEY);
            _cacheManager.RemoveByPattern(PRODUCTVARIANTATTRIBUTEVALUES_PATTERN_KEY);
        }

        #endregion

        #region Goods attribute compinations (goodsSpecCombination)
        
        public virtual void DeleteGoodsSpecCombination(GoodsSpecCombination combination)
        {
            if (combination == null)
                throw new ArgumentNullException("combination");

            _goodsSpecCombinationRepository.Delete(combination);
        }

        public virtual IList<GoodsSpecCombination> GetAllGoodsSpecCombinations(int goodsId)
        {
            if (goodsId == 0)
                return new List<GoodsSpecCombination>();

            var query = from pvac in _goodsSpecCombinationRepository.Table
                        orderby pvac.Id
                        where pvac.GoodsId == goodsId
                        select pvac;
            var combinations = query.ToList();
            return combinations;
        }

        public virtual GoodsSpecCombination GetGoodsSpecCombinationById(int goodsSpecCombinationId)
        {
            if (goodsSpecCombinationId == 0)
                return null;

            var combination = _goodsSpecCombinationRepository.GetById(goodsSpecCombinationId);
            return combination;
        }

        public virtual void InsertGoodsSpecCombination(GoodsSpecCombination combination)
        {
            if (combination == null)
                throw new ArgumentNullException("combination");

            _goodsSpecCombinationRepository.Insert(combination);
        }

        public virtual void UpdateGoodsSpecCombination(GoodsSpecCombination combination)
        {
            if (combination == null)
                throw new ArgumentNullException("combination");

            _goodsSpecCombinationRepository.Update(combination);
        }

        #endregion

        #endregion
    }
}
